using MapsterMapper;
using AiQiuQuan.Sport.Model.Models;
using AiQiuQuan.Sport.Core;
using AiQiuQuan.Sport.WebApi.Entities;
using AiQiuQuan.Sport.WebApi.Repositories;
using Microsoft.EntityFrameworkCore;
using AiQiuQuan.Sport.Model.Enums;
using AiQiuQuan.Sport.WebApi.Core;
using RedLockNet;
using AiQiuQuan.Sport.Core.Tool;
using DotNetCore.CAP;

namespace AiQiuQuan.Sport.WebApi.Services.Impl
{
    /// <summary>
    /// 比赛管理
    /// </summary>
    public partial class GameService : IGameService
    {
        private readonly IMapper _mapper;
        private readonly ICurrentInfo _currentInfo;
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IGameRepository _gameRepository;
        private readonly IGameTeamRepository _gameTeamRepository;
        private readonly IGameGroupRepository _gameGroupRepository;
        private readonly IGameGroupUserRepository _gameGroupUserRepository;
        private readonly IGameGroupVersusRepository _gameGroupVersusRepository;
        private readonly IGameKnockoutRoundsRepository _gameKnockoutRoundsRepository;
        private readonly IGameKnockoutVersusRepository _gameKnockoutVersusRepository;
        private readonly IBaseUserRepository _baseUserRepository;
        private readonly IDistributedLockFactory _distributedLockFactory;
        private readonly IGameOrderRepository _gameOrderRepository;
        private readonly IBaseUserService _baseUserService;
        private readonly IGamePointRuleRepository _gamePointRuleRepository;
        private readonly ICapPublisher _capPublisher;
        private readonly IVenueInfoRepository _venueInfoRepository;
        private readonly IGameManageUserRepository _gameManageUserRepository;
        private readonly IProvinceRepository _provinceRepository;
        private readonly ICityRepository _cityRepository;
        private readonly IPayOrderRepository _payOrderRepository;

        /// <summary>
        /// ctor
        /// </summary>
        public GameService(
            IMapper mapper,
            ICurrentInfo currentInfo,
            IUnitOfWorkManager unitOfWorkManager,
            IGameRepository gameRepository,
            IGameTeamRepository gameTeamRepository,
            IGameGroupRepository gameGroupRepository,
            IGameGroupUserRepository gameGroupUserRepository,
            IGameGroupVersusRepository gameGroupVersusRepository,
            IGameKnockoutRoundsRepository gameKnockoutRoundsRepository,
            IGameKnockoutVersusRepository gameKnockoutVersusRepository,
            IBaseUserRepository baseUserRepository,
            IDistributedLockFactory distributedLockFactory,
            IGameOrderRepository gameOrderRepository,
            IBaseUserService baseUserService,
            IGamePointRuleRepository gamePointRuleRepository,
            ICapPublisher capPublisher,
            IVenueInfoRepository venueInfoRepository,
            IGameManageUserRepository gameManageUserRepository,
            IProvinceRepository provinceRepository,
            ICityRepository cityRepository,
            IPayOrderRepository payOrderRepository)
        {
            _mapper = mapper;
            _currentInfo = currentInfo;
            _unitOfWorkManager = unitOfWorkManager;
            _gameRepository = gameRepository;
            _gameTeamRepository = gameTeamRepository;
            _gameGroupRepository = gameGroupRepository;
            _gameGroupUserRepository = gameGroupUserRepository;
            _gameGroupVersusRepository = gameGroupVersusRepository;
            _gameKnockoutRoundsRepository = gameKnockoutRoundsRepository;
            _gameKnockoutVersusRepository = gameKnockoutVersusRepository;
            _baseUserRepository = baseUserRepository;
            _distributedLockFactory = distributedLockFactory;
            _gameOrderRepository = gameOrderRepository;
            _baseUserService = baseUserService;
            _gamePointRuleRepository = gamePointRuleRepository;
            _capPublisher = capPublisher;
            _venueInfoRepository = venueInfoRepository;
            _gameManageUserRepository = gameManageUserRepository;
            _provinceRepository = provinceRepository;
            _cityRepository = cityRepository;
            _payOrderRepository = payOrderRepository;
        }

        /// <summary>
        /// 查询一条记录
        /// </summary>
        public async Task<GameDto> GetAsync(Guid id)
        {
            var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == id);
            return _mapper.Map<Game, GameDto>(game);
        }

        /// <summary>
        /// 比赛详情
        /// </summary>
        public async Task<GameDto> QueryAsync(GameQueryRequestDto request)
        {
            var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.GameId);
            var result = _mapper.Map<Game, GameDto>(game);
            result.Distance = DistanceTool.GetDistanceKM(result.Lat, result.Lng, request.Lat, request.Lng);
            var teamStateList = new List<GameJoinStateEnum> { GameJoinStateEnum.Joining, GameJoinStateEnum.JoinCompleted };
            var teamlist = await _gameTeamRepository.AsNoTracking().Where(m => m.GameId == request.GameId && teamStateList.Contains(m.JoinState)).ToListAsync();
            result.JoinTeamCount = teamlist.GroupBy(m => m.BusinessId).Count();
            result.TeamList = _mapper.Map<List<GameTeam>, List<GameTeamDto>>(teamlist.DistinctBy(m => m.BusinessId).ToList());
            return result;
        }

        /// <summary>
        /// 比赛分页请求
        /// </summary>
        public async Task<PageResult<GameDto>> PageListAsync(GameQueryPageRequestDto request)
        {
            var queryable = _gameRepository.AsNoTracking();
            if (request.IsOnlyManage.HasValue && request.IsOnlyManage.Value)
            {
                queryable = queryable.Where(m => _gameManageUserRepository.Any(j => j.GameId == m.ID && j.UserId == _currentInfo.UserId));
            }

            if (request.IsOnlySelf.HasValue && request.IsOnlySelf.Value)
            {
                var stateList = new List<GameJoinStateEnum> { GameJoinStateEnum.Joining, GameJoinStateEnum.JoinCompleted };
                queryable = queryable.Where(m => _gameTeamRepository.Any(j => j.GameId == m.ID && stateList.Contains(j.JoinState) && (j.User1Id == _currentInfo.UserId || j.User2Id == _currentInfo.UserId)));
            }

            if (!string.IsNullOrWhiteSpace(request.Name))
            {
                queryable = queryable.Where(m => m.Name.Contains(request.Name));
            }

            if (request.Type.HasValue)
            {
                queryable = queryable.Where(m => m.Type == request.Type.Value);
            }

            if (request.State.HasValue && request.State.Value != 0)
            {
                queryable = queryable.Where(m => m.State == request.State.Value);
            }

            if (request.ProvinceId.HasValue && request.CityId.HasValue)
            {
                queryable = queryable.Where(m => m.ProvinceId == request.ProvinceId && m.CityId == request.CityId);
            }
            else if (request.ProvinceId.HasValue && !request.CityId.HasValue)
            {
                queryable = queryable.Where(m => m.ProvinceId == request.ProvinceId);
            }

            var pagelist = await queryable.OrderByDescending(m => m.CreateTime).PageListAsync<Game, GameDto>(request, _mapper);
            foreach (var item in pagelist.Result)
            {
                if (request.IsPlatform)
                {
                    var teamStateList = new List<GameJoinStateEnum> { GameJoinStateEnum.Joining, GameJoinStateEnum.JoinCompleted };
                    var teamlist = await _gameTeamRepository.AsNoTracking().Where(m => m.GameId == item.ID && teamStateList.Contains(m.JoinState)).ToListAsync();
                    item.JoinTeamCount = teamlist.GroupBy(m => m.BusinessId).Count();
                }
                else
                {
                    item.Distance = DistanceTool.GetDistanceKM(item.Lat, item.Lng, request.Lat, request.Lng);
                }

                if (request.IsOnlySelf.GetValueOrDefault())
                {
                    item.Team = await GetSelfGameTeamAsync(item.ID, _currentInfo.UserId);
                }
            }

            return pagelist;
        }

        /// <summary>
        /// 新增
        /// </summary>
        public async Task<UnaryResult> AddAsync(GameAddDto model)
        {
            var game = CreateGame(model);
            var groupCount = GetGroupCount(game.TeamCount).Item1;
            if (groupCount * game.GroupRank < game.KnockoutRank)
            {
                return UnaryResult.Faild(10, "淘汰赛阶段队伍数不足");
            }

            var venue = await _venueInfoRepository.FirstOrDefaultAsync(m => m.ID == model.VenueId);
            if (venue == null)
            {
                return UnaryResult.Faild(10, "场馆不存在");
            }

            game.VenueName = venue.VI_Name;
            game.ProvinceId = venue.ProvinceID;
            game.ProvinceName = venue.VI_P_Name;
            game.CityId = venue.CityID;
            game.CityName = venue.VI_C_Name;
            game.Lat = venue.VI_Lat.GetValueOrDefault();
            game.Lng = venue.VI_Lng.GetValueOrDefault();

            if (model.FollowProvinceId.HasValue)
            {
                var province = await _provinceRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == model.FollowProvinceId.Value);
                game.FollowProvinceId = province?.ID;
                game.FollowProvinceName = province?.P_Name;
                if (province == null)
                {
                    return UnaryResult.Faild(10, "所属省不正确");
                }
            }

            if (model.FollowCityId.HasValue)
            {
                var city = await _cityRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == model.FollowCityId.Value);
                game.FollowCityId = city?.ID;
                game.FollowCityName = city?.C_Name;
                if (city == null)
                {
                    return UnaryResult.Faild(10, "所属市不正确");
                }
            }

            var groupList = new List<GameGroup>();
            var groupUserList = new List<GameGroupUser>();
            var groupVersusList = new List<GameGroupVersus>();
            var knockoutRoundsList = new List<GameKnockoutRounds>();
            var knockoutVersusList = new List<GameKnockoutVersus>();
            //生成小组赛、淘汰赛对阵及相关数据
            var inner = new GameInnerDto
            {
                GameId = game.ID,
                VersusTypeList = new List<GameVersusEnum>(),
                TeamCount = game.TeamCount,
                GroupRank = game.GroupRank,
                KnockoutRank = game.KnockoutRank,
            };
            foreach (var versusType in model.VersusTypeList)
            {
                inner.VersusTypeList.Clear();
                inner.VersusTypeList.Add(versusType);
                //创建小组、小组成员及小组对阵
                CreateGameGroupUserAndVersus(inner, groupList, groupUserList, groupVersusList);
                //生成淘汰赛轮次及对阵
                CreateGameKnockoutVersus(game, versusType, knockoutRoundsList, knockoutVersusList);
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _gameRepository.AddAsync(game);
                await _gameGroupRepository.BulkAddAsync(groupList);
                await _gameGroupUserRepository.BulkAddAsync(groupUserList);
                await _gameGroupVersusRepository.BulkAddAsync(groupVersusList);
                await _gameKnockoutRoundsRepository.BulkAddAsync(knockoutRoundsList);
                await _gameKnockoutVersusRepository.BulkAddAsync(knockoutVersusList);
                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 修改
        /// </summary>
        public async Task<UnaryResult> UpdateAsync(GameUpdateDto model)
        {
            var game = await _gameRepository.FirstOrDefaultAsync(m => m.ID == model.ID);
            if (game == null)
            {
                return UnaryResult.Faild(10, "不存在");
            }

            if (game.Type != model.Type)
            {
                return UnaryResult.Faild(10, "禁止修改比赛类型");
            }

            if (game.LimitCount != model.LimitCount)
            {
                return UnaryResult.Faild(10, "禁止修改比赛队伍数");
            }

            if (game.GroupRank != model.GroupRank)
            {
                return UnaryResult.Faild(10, "禁止修改比赛小组出线名次");
            }

            if (game.KnockoutRank != model.KnockoutRank)
            {
                return UnaryResult.Faild(10, "禁止修改比赛淘汰赛角逐名次");
            }

            if (game.State == GameStateEnum.Finished || game.State == GameStateEnum.Cancel)
            {
                return UnaryResult.Faild(10, "比赛已结束或已取消");
            }

            var groupCount = GetGroupCount(game.TeamCount).Item1;
            if (groupCount * game.GroupRank < game.KnockoutRank)
            {
                return UnaryResult.Faild(10, "淘汰赛阶段队伍数不足");
            }

            if (await _gameGroupUserRepository.AnyAsync(m => m.GameId == model.ID))
            {
                return UnaryResult.Faild(10, "比赛已开始抽签编排对阵");
            }

            if (game.VenueId != model.VenueId)
            {
                var venue = await _venueInfoRepository.FirstOrDefaultAsync(m => m.ID == model.VenueId);
                if (venue == null)
                {
                    return UnaryResult.Faild(10, "场馆不存在");
                }

                game.VenueName = venue.VI_Name;
                game.ProvinceId = venue.ProvinceID;
                game.ProvinceName = venue.VI_P_Name;
                game.CityId = venue.CityID;
                game.CityName = venue.VI_C_Name;
                game.Lat = venue.VI_Lat.GetValueOrDefault();
                game.Lng = venue.VI_Lng.GetValueOrDefault();
            }

            if (model.FollowProvinceId.HasValue)
            {
                var province = await _provinceRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == model.FollowProvinceId.Value);
                game.FollowProvinceId = province?.ID;
                game.FollowProvinceName = province?.P_Name;
                if (province == null)
                {
                    return UnaryResult.Faild(10, "所属省不正确");
                }
            }

            if (model.FollowCityId.HasValue)
            {
                var city = await _cityRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == model.FollowCityId.Value);
                game.FollowCityId = city?.ID;
                game.FollowCityName = city?.C_Name;
                if (city == null)
                {
                    return UnaryResult.Faild(10, "所属市不正确");
                }
            }

            _mapper.Map(model, game);
            UpdateGame(model, game);
            var groupList = new List<GameGroup>();
            var inner = new GameInnerDto
            {
                GameId = game.ID,
                VersusTypeList = System.Text.Json.JsonSerializer.Deserialize<List<GameVersusEnum>>(game.VersusType),
                TeamCount = game.TeamCount,
                GroupRank = game.GroupRank,
                KnockoutRank = game.KnockoutRank,
            };

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _gameRepository.UpdateAsync(game);
                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 比赛状态修改
        /// </summary>
        public async Task<UnaryResult> UpdateGameStateAsync(GameStateUpdateDto request)
        {
            var game = await _gameRepository.FirstOrDefaultAsync(m => m.ID == request.ID);
            if (game == null)
            {
                return UnaryResult.Faild(10, "比赛不存在");
            }

            if (game.State == GameStateEnum.Finished || game.State == GameStateEnum.Cancel)
            {
                return UnaryResult.Faild(10, "比赛已结束或取消");
            }

            game.State = request.State;
            await _gameRepository.UpdateAsync(game);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 增加比赛管理员
        /// </summary>
        public async Task<UnaryResult> AddManageUserAsync(GameManageUserAddDto request)
        {
            if (!await _gameRepository.AnyAsync(m => m.ID == request.GameId))
            {
                return UnaryResult.Faild(10, "比赛不存在");
            }

            var list = new List<GameManageUser>();
            foreach (var item in request.UserIdList)
            {
                if (await _gameManageUserRepository.AnyAsync(m => m.GameId == request.GameId && m.UserId == item))
                {
                    return UnaryResult.Faild(10, "用户重复");
                }

                list.Add(new GameManageUser { GameId = request.GameId, UserId = item });
            }

            await _gameManageUserRepository.BulkAddAsync(list);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 删除比赛管理员
        /// </summary>
        public async Task<UnaryResult> DeleteManageUserAsync(GameManageUserDeleteDto request)
        {
            await _gameManageUserRepository.DeleteAsync(m => m.GameId == request.GameId && m.UserId == request.UserId);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 获取比赛管理员
        /// </summary>
        /// <param name="gameId">比赛ID</param>
        public async Task<List<GameManageUserDto>> GetGameManageUserListAsync(Guid gameId)
        {
            var queryable = from manage in _gameManageUserRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on manage.UserId equals user.ID
                            where manage.GameId == gameId
                            select new GameManageUserDto
                            {
                                ID = manage.ID,
                                GameId = manage.GameId,
                                UserId = manage.UserId,
                                CreateTime = manage.CreateTime,
                                UserCode = user.U_Code,
                                NickName = user.U_NickName,
                                RealName = user.U_RealName,
                                Phone = user.U_PhoneNum
                            };
            return await queryable.ToListAsync();
        }

        /// <summary>
        /// 删除
        /// </summary>
        public async Task<UnaryResult> DeleteAsync(Guid id)
        {
            await _gameRepository.DeleteAsync(p => p.ID == id);

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 比赛报名
        /// </summary>
        public async Task<UnaryResult<GameJoinResultDto>> JoinAsync(GameJoinRequestDto request)
        {
            var result = new GameJoinResultDto { GameId = request.GameId };
            await using (var redlock = await _distributedLockFactory.CreateLockAsync(request.GameId.ToString("N"), TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(8), TimeSpan.FromSeconds(1)))
            {
                //验证
                var unaryResult = await ValidJoinAsync(request);
                if (unaryResult.Code != 0)
                {
                    return unaryResult;
                }

                var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => request.GameId == m.ID);
                //生成比赛业务订单
                var gameOrder = await CreateGameOrderAsync(request, game);
                //生成队伍列表
                var teamList = await CreateGameTeamAsync(request, game, gameOrder);
                result.GameOrderId = gameOrder.ID;
                result.GameOrderNo = gameOrder.OrderNo;

                using (var uow = _unitOfWorkManager.Begin())
                {
                    await _gameTeamRepository.BulkAddAsync(teamList);
                    await _gameOrderRepository.AddAsync(gameOrder);
                    await uow.CompleteAsync();
                }
            }

            return UnaryResult.Succeed(result);
        }

        /// <summary>
        /// 获取小组抽签信息
        /// </summary>
        public async Task<GameGroupDrawInfoDto> GetGroupDrawInfoAsync(GameRequestDto request)
        {
            var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.GameId);
            if (game == null)
            {
                return null;
            }

            var groupInfo = GetGroupCount(game.TeamCount);
            var result = new GameGroupDrawInfoDto
            {
                GameId = game.ID,
                VersusType = request.VersusType,
                IsTogether = game.IsTogether,
                GroupUserCount = game.IsTogether ? groupInfo.Item2 : groupInfo.Item2 * 2,
                TeamNoList = GetTeamNoList(groupInfo.Item2),
                GroupNoList = GetGroupNoList(game.TeamCount),
                TeamList = await GetGroupDrawTeamListAsync(request)
            };

            return result;
        }

        /// <summary>
        /// 小组自动抽签
        /// </summary>
        public async Task<List<GameGroupDrawTeamDto>> GroupAutoDrawAsync(GameRequestDto request)
        {
            var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == request.GameId);
            var teamList = await GetGroupDrawTeamListAsync(request);
            SetGroupAutoDrawData(teamList, game);

            return teamList;
        }

        /// <summary>
        /// 非团体比赛队伍列表
        /// </summary>
        public async Task<List<GameTeamDto>> GetSingleGameTeamListAsync(GameTeamSingleRequestDto request)
        {
            var stateList = new List<GameJoinStateEnum> { GameJoinStateEnum.JoinCompleted, GameJoinStateEnum.Joining };
            var quaryable = from team in _gameTeamRepository.AsNoTracking()
                            join user1 in _baseUserRepository.AsNoTracking()
                            on team.User1Id equals user1.ID into user1d
                            from user1 in user1d.DefaultIfEmpty()
                            join user2 in _baseUserRepository.AsNoTracking()
                            on team.User2Id equals user2.ID into user2d
                            from user2 in user2d.DefaultIfEmpty()
                            where team.GameId == request.GameId && stateList.Contains(team.JoinState)
                            select new GameTeamDto
                            {
                                ID = team.ID,
                                GameId = team.GameId,
                                BusinessId = team.BusinessId,
                                VersusType = team.VersusType,
                                GameOrderId = team.GameOrderId,
                                Name = team.Name,
                                HeadUrl = team.HeadUrl,
                                GroupNo = team.GroupNo,
                                TeamNo = team.TeamNo,
                                User1Id = team.User1Id,
                                User1Code = user1.U_Code,
                                User1Name = user1.U_RealName ?? user1.U_NickName,
                                User1HeadUrl = user1.U_Headportrait,
                                User1TennisLevel = "1.0",
                                User2Id = team.User2Id,
                                User2Code = user2.U_Code,
                                User2Name = user2.U_RealName ?? user2.U_NickName,
                                User2HeadUrl = user2.U_Headportrait,
                                User2TennisLevel = "1.0",
                                JoinState = team.JoinState,
                                PayState = team.PayState,
                                CreateTime = team.CreateTime
                            };
            var teamlist = await quaryable.ToListAsync();
            foreach (var item in teamlist)
            {
                item.User1TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User1Id)).LevelName;
                if (item.User2Id.HasValue)
                {
                    item.User2TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User2Id.GetValueOrDefault())).LevelName;
                }
            }

            return teamlist;
        }

        /// <summary>
        /// PC端非团体比赛队伍列表
        /// </summary>
        public async Task<List<GameTeamDto>> GetSingleGameTeamListPCAsync(GameTeamSingleRequestDto request)
        {
            var paySateList = new List<PayOrderStateEnum> { PayOrderStateEnum.Paid, PayOrderStateEnum.Refunded, PayOrderStateEnum.PartialRefunded };
            var quaryable = from team in _gameTeamRepository.AsNoTracking()
                            join user1 in _baseUserRepository.AsNoTracking()
                            on team.User1Id equals user1.ID into user1d
                            from user1 in user1d.DefaultIfEmpty()
                            join user2 in _baseUserRepository.AsNoTracking()
                            on team.User2Id equals user2.ID into user2d
                            from user2 in user2d.DefaultIfEmpty()
                            join user3 in _baseUserRepository.AsNoTracking()
                            on team.JoinUserId equals user3.ID into user3d
                            from user3 in user3d.DefaultIfEmpty()
                            join payorder in _payOrderRepository.AsNoTracking()
                            on team.GameOrderId equals payorder.BusinessId into payorderd
                            from payorder in payorderd.DefaultIfEmpty()
                            where team.GameId == request.GameId
                            select new GameTeamDto
                            {
                                ID = team.ID,
                                GameId = team.GameId,
                                BusinessId = team.BusinessId,
                                VersusType = team.VersusType,
                                Name = team.Name,
                                GameOrderId = team.GameOrderId,
                                HeadUrl = team.HeadUrl,
                                GroupNo = team.GroupNo,
                                TeamNo = team.TeamNo,
                                User1Id = team.User1Id,
                                User1Code = user1.U_Code,
                                User1Name = user1.U_RealName ?? user1.U_NickName,
                                User1HeadUrl = user1.U_Headportrait,
                                User1TennisLevel = "1.0",
                                User2Id = team.User2Id,
                                User2Code = user2.U_Code,
                                User2Name = user2.U_RealName ?? user2.U_NickName,
                                User2HeadUrl = user2.U_Headportrait,
                                User2TennisLevel = "1.0",
                                JoinState = team.JoinState,
                                PayState = team.PayState,
                                JoinUserCode = user3.U_Code,
                                PayAmount = paySateList.Contains(payorder.PayState) ? payorder.PayAmount : 0,
                                RefundAmount = paySateList.Contains(payorder.PayState) ? payorder.RefundAmount : 0,
                                CreateTime = team.CreateTime
                            };
            var teamlist = await quaryable.ToListAsync();
            foreach (var item in teamlist)
            {
                item.User1TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User1Id)).LevelName;
                if (item.User2Id.HasValue)
                {
                    item.User2TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User2Id.GetValueOrDefault())).LevelName;
                }
            }

            return teamlist;
        }

        /// <summary>
        /// 团体比赛队伍概要列表
        /// </summary>
        public async Task<List<GameTeamSimpleDto>> GetSimpleGameTeamListAsync(GameTeamRequestDto request)
        {
            var stateList = new List<GameJoinStateEnum> { GameJoinStateEnum.JoinCompleted, GameJoinStateEnum.Joining };
            var quaryable = from team in _gameTeamRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on team.JoinUserId equals user.ID into userd
                            from user in userd.DefaultIfEmpty()
                            where team.GameId == request.GameId && stateList.Contains(team.JoinState)
                            select new GameTeamSimpleDto
                            {
                                ID = team.ID,
                                GameId = team.GameId,
                                BusinessId = team.BusinessId,
                                GameOrderId = team.GameOrderId,
                                Name = team.Name,
                                HeadUrl = team.HeadUrl,
                                JoinUserId = team.JoinUserId,
                                JoinState = team.JoinState,
                                PayState = team.PayState,
                                JoinUserName = user.U_RealName ?? user.U_NickName,
                                Point = team.Point,
                                CreateTime = team.CreateTime
                            };
            var teamlist = await quaryable.ToListAsync();
            teamlist = teamlist.GroupBy(m => m.BusinessId).Select(m => new GameTeamSimpleDto
            {
                GameId = m.First().GameId,
                BusinessId = m.Key,
                Name = m.First().Name,
                HeadUrl = m.First().HeadUrl,
                JoinState = m.First().JoinState,
                PayState = m.First().PayState,
                JoinUserId = m.First().JoinUserId,
                JoinUserName = m.First().JoinUserName,
                Point = m.Sum(m => m.Point),
                CreateTime = m.First().CreateTime,
            }).OrderByDescending(m => m.Point).ToList();
            if (teamlist.Any(m => m.Point > 0))
            {
                var rank = 1;
                for (var i = 0; i < teamlist.Count; i++)
                {
                    if (i > 0 && teamlist[i].Point != teamlist[i - 1].Point)
                    {
                        rank++;
                    }

                    teamlist[i].PointRank = rank;
                }
            }

            return teamlist;
        }

        /// <summary>
        /// PC端团体比赛队伍概要列表
        /// </summary>
        public async Task<List<GameTeamSimpleDto>> GetSimpleGameTeamListPCAsync(GameTeamRequestDto request)
        {
            var quaryable = from team in _gameTeamRepository.AsNoTracking()
                            join user in _baseUserRepository.AsNoTracking()
                            on team.JoinUserId equals user.ID into userd
                            from user in userd.DefaultIfEmpty()
                            where team.GameId == request.GameId
                            select new GameTeamSimpleDto
                            {
                                ID = team.ID,
                                GameId = team.GameId,
                                BusinessId = team.BusinessId,
                                GameOrderId = team.GameOrderId,
                                Name = team.Name,
                                HeadUrl = team.HeadUrl,
                                JoinUserId = team.JoinUserId,
                                JoinState = team.JoinState,
                                PayState = team.PayState,
                                JoinUserName = user.U_RealName ?? user.U_NickName,
                                JoinUserCode = user.U_Code,
                                CreateTime = team.CreateTime
                            };
            var teamlist = await quaryable.ToListAsync();
            teamlist = teamlist.GroupBy(m => m.BusinessId).Select(m => new GameTeamSimpleDto
            {
                GameId = m.First().GameId,
                BusinessId = m.Key,
                Name = m.First().Name,
                GameOrderId = m.First().GameOrderId,
                HeadUrl = m.First().HeadUrl,
                JoinState = m.First().JoinState,
                PayState = m.First().PayState,
                JoinUserId = m.First().JoinUserId,
                JoinUserName = m.First().JoinUserName,
                JoinUserCode = m.First().JoinUserCode,
                CreateTime = m.First().CreateTime,
            }).ToList();
            if (teamlist.Any())
            {
                var paySateList = new List<PayOrderStateEnum> { PayOrderStateEnum.Paid, PayOrderStateEnum.Refunded, PayOrderStateEnum.PartialRefunded };
                var orderIdList = teamlist.Select(m => m.GameOrderId).ToList();
                var payorderList = await _payOrderRepository.AsNoTracking().Where(m => orderIdList.Contains(m.BusinessId) && paySateList.Contains(m.PayState)).ToListAsync();
                foreach (var item in payorderList)
                {
                    var team = teamlist.First(m => m.GameOrderId == item.BusinessId);
                    team.PayAmount = item.PayAmount;
                    team.RefundAmount = item.RefundAmount;
                }
            }

            return teamlist;
        }

        /// <summary>
        /// 团体比赛队伍列表
        /// </summary>
        /// <param name="businessId">队伍业务ID</param>
        public async Task<List<GameTeamDto>> GetGameTeamListAsync(Guid businessId)
        {
            var quaryable = from team in _gameTeamRepository.AsNoTracking()
                            join user1 in _baseUserRepository.AsNoTracking()
                            on team.User1Id equals user1.ID into user1d
                            from user1 in user1d.DefaultIfEmpty()
                            join user2 in _baseUserRepository.AsNoTracking()
                            on team.User2Id equals user2.ID into user2d
                            from user2 in user2d.DefaultIfEmpty()
                            where team.BusinessId == businessId
                            select new GameTeamDto
                            {
                                ID = team.ID,
                                GameId = team.GameId,
                                BusinessId = team.BusinessId,
                                VersusType = team.VersusType,
                                Name = team.Name,
                                HeadUrl = team.HeadUrl,
                                GroupNo = team.GroupNo,
                                TeamNo = team.TeamNo,
                                User1Id = team.User1Id,
                                User1Name = user1.U_RealName ?? user1.U_NickName,
                                User1HeadUrl = user1.U_Headportrait,
                                User1TennisLevel = "1.0",
                                User2Id = team.User2Id,
                                User2Name = user2.U_RealName ?? user2.U_NickName,
                                User2HeadUrl = user2.U_Headportrait,
                                User2TennisLevel = "1.0",
                                Point = team.Point,
                                CreateTime = team.CreateTime
                            };
            var teamlist = await quaryable.ToListAsync();
            foreach (var item in teamlist)
            {
                item.User1TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User1Id)).LevelName;
                if (item.User2Id.HasValue)
                {
                    item.User2TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User2Id.GetValueOrDefault())).LevelName;
                }

                if (!string.IsNullOrWhiteSpace(item.TeamNo))
                {
                    await SetTeamKnockoutRankAsync(item);
                }
            }

            return teamlist;
        }

        /// <summary>
        /// PC端团体比赛队伍列表
        /// </summary>
        /// <param name="businessId">队伍业务ID</param>
        public async Task<List<GameTeamDto>> GetGameTeamListPCAsync(Guid businessId)
        {
            var quaryable = from team in _gameTeamRepository.AsNoTracking()
                            join user1 in _baseUserRepository.AsNoTracking()
                            on team.User1Id equals user1.ID into user1d
                            from user1 in user1d.DefaultIfEmpty()
                            join user2 in _baseUserRepository.AsNoTracking()
                            on team.User2Id equals user2.ID into user2d
                            from user2 in user2d.DefaultIfEmpty()
                            where team.BusinessId == businessId
                            select new GameTeamDto
                            {
                                ID = team.ID,
                                GameId = team.GameId,
                                BusinessId = team.BusinessId,
                                VersusType = team.VersusType,
                                Name = team.Name,
                                HeadUrl = team.HeadUrl,
                                GroupNo = team.GroupNo,
                                GameOrderId = team.GameOrderId,
                                TeamNo = team.TeamNo,
                                User1Id = team.User1Id,
                                User1Name = user1.U_RealName ?? user1.U_NickName,
                                User1HeadUrl = user1.U_Headportrait,
                                User1TennisLevel = "1.0",
                                User2Id = team.User2Id,
                                User2Name = user2.U_RealName ?? user2.U_NickName,
                                User2HeadUrl = user2.U_Headportrait,
                                User2TennisLevel = "1.0",
                                CreateTime = team.CreateTime
                            };
            var teamlist = await quaryable.ToListAsync();
            foreach (var item in teamlist)
            {
                item.User1TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User1Id)).LevelName;
                if (item.User2Id.HasValue)
                {
                    item.User2TennisLevel = (await _baseUserService.GetTennisLevelAsync(item.User2Id.GetValueOrDefault())).LevelName;
                }
            }

            return teamlist;
        }

        /// <summary>
        /// 小组信息更改
        /// </summary>
        public async Task<UnaryResult> UpdateGroupAsync(GameGroupUpdateDto request)
        {
            var group = await _gameGroupRepository.FirstOrDefaultAsync(m => m.ID == request.ID);
            if (group == null)
            {
                return UnaryResult.Faild(10, "小组不存在");
            }

            group.StartTime = request.StartTime ?? group.StartTime;
            group.EndTime = request.EndTime ?? group.EndTime;
            group.Address = request.Address ?? group.Address;
            await _gameGroupRepository.UpdateAsync(group);
            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 更新队伍头像
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<UnaryResult> UpdateTeamHeadUrlAsync(GameTeamHeadUrlRequestDto request)
        {
            var builder = await _gameTeamRepository.UpdatePartialAsync();
            builder = builder.Set(m => m.HeadUrl, request.HeadUrl).Where(m => m.GameId == request.GameId && m.VersusType == request.VersusType && m.TeamNo == request.TeamNo);
            await builder.ExecuteAsync();

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 结束小组赛
        /// </summary>
        /// <param name="groupId">小组ID</param>
        public async Task<UnaryResult> FinishGameGroupAsync(Guid groupId)
        {
            if (await _gameGroupVersusRepository.AnyAsync(m => m.GroupId == groupId && m.Team1Score == 0 && m.Team2Score == 0))
            {
                return UnaryResult.Faild(10, "小组比赛对阵未全部完成");
            }

            var groupBuilder = await _gameGroupRepository.UpdatePartialAsync();
            groupBuilder = groupBuilder.Set(m => m.IsFinished, true).Where(m => m.ID == groupId);
            var groupVersusBuilder = await _gameGroupVersusRepository.UpdatePartialAsync();
            groupVersusBuilder = groupVersusBuilder.Set(m => m.IsFinished, true).Where(m => m.GroupId == groupId);
            using (var uow = _unitOfWorkManager.Begin())
            {
                await groupBuilder.ExecuteAsync();
                await groupVersusBuilder.ExecuteAsync();
                await uow.CompleteAsync();
            }

            //初始化淘汰赛阶段首轮数据
            var group = await _gameGroupRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == groupId);
            if (group != null)
            {
                var request = new GameKnockoutVersusInitDto
                {
                    GameId = group.GameId,
                    VersusType = group.VersusType
                };
                await InitFirstKnockoutVersusMember(request);
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 获取比赛小组列表
        /// </summary>
        public async Task<List<GameGroupDto>> GetGameGroupListAsync(GameGroupRequestDto request)
        {
            var groupList = await _gameGroupRepository.AsNoTracking()
                .Where(m => m.GameId == request.GameId && m.VersusType == request.VersusType).OrderBy(m => m.GroupNo)
                .Select(m => _mapper.Map<GameGroupDto>(m)).ToListAsync();
            if (request.IsIncludeUser.GetValueOrDefault())
            {
                foreach (var item in groupList)
                {
                    item.GroupUserList = await GetGroupUserListAsync(item.ID);
                }
            }

            return groupList;
        }

        /// <summary>
        /// 获取小组信息及对阵信息列表
        /// </summary>
        public async Task<List<GameGroupDto>> GetGameGroupAndVersusListAsync(GameGroupRequestDto request)
        {
            var queryable = _gameGroupRepository.AsNoTracking()
                .Where(m => m.GameId == request.GameId && m.VersusType == request.VersusType);
            if (request.GroupNo.HasValue)
            {
                queryable = queryable.Where(m => m.GroupNo == request.GroupNo);
            }

            var groupList = await queryable.Select(m => _mapper.Map<GameGroupDto>(m)).ToListAsync();
            foreach (var group in groupList)
            {
                if (request.IsIncludeUser.HasValue && request.IsIncludeUser.Value)
                {
                    group.GroupUserList = await GetGroupUserListAsync(group.ID);
                }

                group.GroupVersusList = await _gameGroupVersusRepository.AsNoTracking()
                    .Where(m => m.GameId == group.GameId && m.VersusType == group.VersusType && m.GroupNo == group.GroupNo)
                    .Select(m => _mapper.Map<GameGroupVersusDto>(m)).ToListAsync();
            }

            return groupList;
        }

        /// <summary>
        /// 获取小组成员信息
        /// </summary>
        /// <param name="groupUserId">组成员ID</param>
        public async Task<GameGroupUserDto> GetGameGroupUserInfoAsync(Guid groupUserId)
        {
            var quaryable = from groupUser in _gameGroupUserRepository.AsNoTracking()
                            join user1 in _baseUserRepository.AsNoTracking()
                            on groupUser.User1Id equals user1.ID into user1d
                            from user1 in user1d.DefaultIfEmpty()
                            join user2 in _baseUserRepository.AsNoTracking()
                            on groupUser.User2Id equals user2.ID into user2d
                            from user2 in user2d.DefaultIfEmpty()
                            join team in _gameTeamRepository.AsNoTracking()
                            on new { groupUser.GameId, groupUser.VersusType, groupUser.GroupNo, groupUser.TeamNo } equals new { team.GameId, team.VersusType, team.GroupNo, team.TeamNo }
                            where groupUser.ID == groupUserId
                            select new GameGroupUserDto
                            {
                                ID = groupUser.ID,
                                GameId = groupUser.GameId,
                                VersusType = groupUser.VersusType,
                                HeadUrl = team.HeadUrl,
                                GroupNo = groupUser.GroupNo,
                                TeamNo = groupUser.TeamNo,
                                User1Id = groupUser.User1Id,
                                User1Name = user1.U_RealName ?? user1.U_NickName,
                                User2Id = groupUser.User2Id,
                                User2Name = user2.U_RealName ?? user2.U_NickName,
                                CreateTime = groupUser.CreateTime
                            };
            var result = await quaryable.FirstOrDefaultAsync();
            return result;
        }

        /// <summary>
        /// 保存小组抽签
        /// </summary>
        public async Task<UnaryResult> SaveGroupDrawLotsAsync(GameGroupDrawLotsRequestDto request)
        {
            var gameId = request.GameId;
            var versusType = request.VersusType;
            var game = await _gameRepository.FirstOrDefaultAsync(m => m.ID == gameId);
            if (game == null)
            {
                return UnaryResult.Faild(10, "比赛不存在");
            }

            var unaryResult = await ValidGroupDrawAsync(request, game, versusType);
            if (unaryResult.Code != 0)
            {
                return unaryResult;
            }

            var groupUserList = new List<GameGroupUser>();
            var groupVersusList = new List<GameGroupVersus>();
            var inner = new GameInnerDto
            {
                GameId = game.ID,
                VersusTypeList = new List<GameVersusEnum> { versusType },
                KnockoutRank = game.KnockoutRank,
                GroupRank = game.GroupRank,
                TeamCount = game.TeamCount
            };
            //更新小组成员级小组对阵
            await CreateGameGroupUserAndVersusAsync(inner, request, groupUserList, groupVersusList);

            using (var uow = _unitOfWorkManager.Begin())
            {
                foreach (var item in groupUserList)
                {
                    await _gameGroupUserRepository.UpdateAsync(item);
                }

                foreach (var item in groupVersusList)
                {
                    await _gameGroupVersusRepository.UpdateAsync(item);
                }

                var clearBuilder = await _gameTeamRepository.UpdatePartialAsync();
                await clearBuilder.Set(m => m.GroupNo, 0).Set(m => m.TeamNo, "")
                    .Where(m => m.GameId == gameId && m.VersusType == versusType).ExecuteAsync();
                foreach (var item in request.TeamList)
                {
                    var builder = await _gameTeamRepository.UpdatePartialAsync();
                    await builder.Set(m => m.GroupNo, item.GroupNo).Set(m => m.TeamNo, $"{item.GroupNo}{item.TeamNo}").Where(m => m.ID == item.Id).ExecuteAsync();
                }

                if (game.State == GameStateEnum.Joining)
                {
                    game.State = GameStateEnum.Processing;
                    await _gameRepository.UpdateAsync(game);
                }

                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 小组比分输入
        /// </summary>
        public async Task<UnaryResult> FinishGroupVersusAsync(GameGroupVersusScoreAddDto request)
        {
            var versus = await _gameGroupVersusRepository.FirstOrDefaultAsync(m => m.ID == request.GroupVersusId);
            if (versus == null)
            {
                return UnaryResult.Faild(10, "小组对阵不存在");
            }

            if (await _gameGroupRepository.AnyAsync(m => m.ID == versus.GroupId && m.IsFinished))
            {
                return UnaryResult.Faild(10, $"小组[{versus.GroupNo}]比赛已结束");
            }

            request.OldTeam1Score = versus.Team1Score + versus.Team1ExtraScore;
            request.OldTeam2Score = versus.Team2Score + versus.Team2ExtraScore;

            versus.Team1Score = request.Team1Score;
            versus.Team2Score = request.Team2Score;
            versus.Team1ExtraScore = request.Team1ExtraScore.GetValueOrDefault();
            versus.Team2ExtraScore = request.Team2ExtraScore.GetValueOrDefault();

            var team1Total = versus.Team1Score + versus.Team1ExtraScore;
            var team2Total = versus.Team2Score + versus.Team2ExtraScore;

            //小组成员相关数据计算赋值
            var groupUser1 = await _gameGroupUserRepository
                .FirstOrDefaultAsync(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.GroupNo == versus.GroupNo && m.TeamNo == versus.Team1No);
            groupUser1.Score = groupUser1.Score - request.OldTeam1Score + team1Total;
            groupUser1.DiffScore = groupUser1.DiffScore - (request.OldTeam1Score - request.OldTeam2Score) + (team1Total - team2Total);
            groupUser1.WinCount = groupUser1.WinCount - (request.OldTeam1Score > request.OldTeam2Score ? 1 : 0) + (team1Total > team2Total ? 1 : 0);
            groupUser1.LoseCount = groupUser1.LoseCount - (request.OldTeam1Score < request.OldTeam2Score ? 1 : 0) + (team1Total < team2Total ? 1 : 0);

            var groupUser2 = await _gameGroupUserRepository
                .FirstOrDefaultAsync(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.GroupNo == versus.GroupNo && m.TeamNo == versus.Team2No);
            groupUser2.Score = groupUser2.Score - request.OldTeam2Score + team2Total;
            groupUser2.DiffScore = groupUser2.DiffScore - (request.OldTeam2Score - request.OldTeam1Score) + (team2Total - team1Total);
            groupUser2.WinCount = groupUser2.WinCount - (request.OldTeam1Score < request.OldTeam2Score ? 1 : 0) + (team1Total < team2Total ? 1 : 0);
            groupUser2.LoseCount = groupUser2.LoseCount - (request.OldTeam1Score > request.OldTeam2Score ? 1 : 0) + (team1Total > team2Total ? 1 : 0);

            //队伍得分更新
            var team1Builder = await _gameTeamRepository.UpdatePartialAsync();
            team1Builder = team1Builder.Set(m => m.Score, m => m.Score - request.OldTeam1Score + team1Total)
                .Where(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.GroupNo == versus.GroupNo && m.TeamNo == versus.Team1No);
            var team2Builder = await _gameTeamRepository.UpdatePartialAsync();
            team2Builder = team2Builder.Set(m => m.Score, m => m.Score - request.OldTeam2Score + team2Total)
                .Where(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.GroupNo == versus.GroupNo && m.TeamNo == versus.Team2No);

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _gameGroupVersusRepository.UpdateAsync(versus);
                await _gameGroupUserRepository.UpdateAsync(groupUser1);
                await _gameGroupUserRepository.UpdateAsync(groupUser2);
                await team1Builder.ExecuteAsync();
                await team2Builder.ExecuteAsync();
                await uow.CompleteAsync();
            }

            //计算本组排名,得分
            var rankModel = new GameGroupRankRequestDto
            {
                GameId = versus.GameId,
                VersusType = versus.VersusType,
                GroupNo = versus.GroupNo
            };
            await CalculateGroupRankAsync(rankModel);

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 小组排名计算
        /// </summary>
        public async Task<UnaryResult> CalculateGroupRankAsync(GameGroupRankRequestDto request)
        {
            var queryable = _gameGroupUserRepository.Where(m => m.GameId == request.GameId && m.VersusType == request.VersusType);
            if (request.GroupNo.GetValueOrDefault() > 0)
            {
                queryable = queryable.Where(m => m.GroupNo == request.GroupNo.Value);
            }

            var groupUserList = await queryable.ToListAsync();
            var updateBuilderList = new List<BatchUpdateBuilder<GameGroupUser>>();
            foreach (var item in groupUserList.GroupBy(m => m.GroupNo))
            {
                var tempList = item.OrderByDescending(m => m.WinCount).ThenByDescending(m => m.DiffScore).ThenByDescending(m => m.Score).ToList();
                for (var i = 1; i <= tempList.Count; i++)
                {
                    var groupUserId = tempList[i - 1].ID;
                    var builder = await _gameGroupUserRepository.UpdatePartialAsync();
                    builder = builder.Set(m => m.Rank, i).Where(m => m.ID == groupUserId);
                    updateBuilderList.Add(builder);
                }
            }

            using (var uow = _unitOfWorkManager.Begin())
            {
                foreach (var builder in updateBuilderList)
                {
                    await builder.ExecuteAsync();
                }

                await uow.CompleteAsync();
            }

            ////小组计算排名后，初始化首轮淘汰赛成员
            //var model = new GameKnockoutVersusInitDto { GameId = request.GameId, VersusType = request.VersusType };
            //var unaryResult = await InitFirstKnockoutVersusMember(model);

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 初始化淘汰赛首轮成员
        /// </summary>
        public async Task<UnaryResult> InitFirstKnockoutVersusMember(GameKnockoutVersusInitDto request)
        {
            if (await _gameGroupRepository.AsNoTracking().AnyAsync(m => m.GameId == request.GameId && m.VersusType == request.VersusType && !m.IsFinished))
            {
                return UnaryResult.Faild(10, "小组赛未完成");
            }

            var groupUserList = await _gameGroupUserRepository.AsNoTracking().Where(m => m.GameId == request.GameId && m.VersusType == request.VersusType).ToListAsync();
            if (groupUserList.Any(m => m.Rank <= 0))
            {
                return UnaryResult.Faild(10, "小组未计算排名");
            }

            if (await _gameKnockoutVersusRepository.AsNoTracking().AnyAsync(m => m.GameId == request.GameId && m.VersusType == request.VersusType && m.IsFinished))
            {
                return UnaryResult.Faild(10, "淘汰赛已开始");
            }

            var firstKonockoutVersusList = await SetFirstKnockoutVersusMember(request, groupUserList);

            using (var uow = _unitOfWorkManager.Begin())
            {
                foreach (var item in firstKonockoutVersusList)
                {
                    await _gameKnockoutVersusRepository.UpdateAsync(item);
                }

                await uow.CompleteAsync();
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 淘汰赛比分输入
        /// </summary>
        public async Task<UnaryResult> FinishKnockoutVersusAsync(GameKnockoutVersusScoreAddDto request)
        {
            var versus = await _gameKnockoutVersusRepository.FirstOrDefaultAsync(m => m.ID == request.KnockoutVersusId);
            if (versus == null)
            {
                return UnaryResult.Faild(10, "淘汰赛对阵不存在");
            }

            if (await _gameGroupRepository.AnyAsync(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && !m.IsFinished))
            {
                return UnaryResult.Faild(10, "小组赛未完成");
            }

            if (await _gameKnockoutRoundsRepository.AnyAsync(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.KnockoutCount == versus.KnockoutCount * 2 && !m.IsFinished))
            {
                return UnaryResult.Faild(10, "淘汰赛上个轮次未结束");
            }

            request.OldTeam1Score = versus.Team1Score + versus.Team1ExtraScore;
            request.OldTeam2Score = versus.Team2Score + versus.Team2ExtraScore;

            versus.Team1Score = request.Team1Score;
            versus.Team2Score = request.Team2Score;
            versus.Team1ExtraScore = request.Team1ExtraScore.GetValueOrDefault();
            versus.Team2ExtraScore = request.Team2ExtraScore.GetValueOrDefault();

            var team1Total = versus.Team1Score + versus.Team1ExtraScore;
            var team2Total = versus.Team2Score + versus.Team2ExtraScore;

            var team1Builder = await _gameTeamRepository.UpdatePartialAsync();
            team1Builder = team1Builder.Set(m => m.Score, m => m.Score - request.OldTeam1Score + team1Total)
                .Where(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.TeamNo == versus.Team1No);
            var team2Builder = await _gameTeamRepository.UpdatePartialAsync();
            team2Builder = team2Builder.Set(m => m.Score, m => m.Score - request.OldTeam2Score + team2Total)
                .Where(m => m.GameId == versus.GameId && m.VersusType == versus.VersusType && m.TeamNo == versus.Team2No);

            using (var uow = _unitOfWorkManager.Begin())
            {
                await _gameKnockoutVersusRepository.UpdateAsync(versus);
                await team1Builder.ExecuteAsync();
                await team2Builder.ExecuteAsync();
                await uow.CompleteAsync();
            }

            //进入下一轮
            await EnterKnockouVersusNexLoopAsync(versus);

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 获取比赛轮次列表
        /// </summary>
        public async Task<List<GameKnockoutRoundsDto>> GetGameRoundsListAsync(GameRequestDto request)
        {
            var list = await _gameKnockoutRoundsRepository.AsNoTracking()
                .Where(m => m.GameId == request.GameId && m.VersusType == request.VersusType)
                .OrderByDescending(m => m.KnockoutCount)
                .Select(m => _mapper.Map<GameKnockoutRoundsDto>(m)).ToListAsync();

            return list;
        }

        /// <summary>
        /// 淘汰赛对阵列表
        /// </summary>
        public async Task<List<GameKnockoutVersusDto>> GetGameKnockoutVersusListAsync(GameKnockoutVersusRequestDto request)
        {
            var queryable = from versus in _gameKnockoutVersusRepository.AsNoTracking()
                            join team1 in _gameTeamRepository.AsNoTracking()
                            on new { versus.GameId, versus.VersusType, c = versus.Team1No } equals new { team1.GameId, team1.VersusType, c = team1.TeamNo } into team1d
                            from team1 in team1d.DefaultIfEmpty()
                            join team2 in _gameTeamRepository.AsNoTracking()
                            on new { versus.GameId, versus.VersusType, c = versus.Team2No } equals new { team2.GameId, team2.VersusType, c = team2.TeamNo } into team2d
                            from team2 in team2d.DefaultIfEmpty()
                            where versus.GameId == request.GameId && versus.VersusType == request.VersusType && versus.KnockoutRoundsId == request.RoundsId
                            select new GameKnockoutVersusDto
                            {
                                ID = versus.ID,
                                GameId = versus.GameId,
                                VersusType = versus.VersusType,
                                KnockoutRoundsId = versus.KnockoutRoundsId,
                                KnockoutCount = versus.KnockoutCount,
                                KnockoutName = versus.KnockoutName,
                                LoopNo = versus.LoopNo,
                                IsDouble = versus.IsDouble,
                                IsExtra = versus.IsExtra,
                                IsFinished = versus.IsFinished,
                                StartRank = versus.StartRank,
                                EndRank = versus.EndRank,
                                Address = versus.Address,
                                StartTime = versus.StartTime,
                                EndTime = versus.EndTime,
                                Team1No = versus.Team1No,
                                Team1HeadUrl = team1.HeadUrl,
                                Team1User1Id = versus.Team1User1Id,
                                Team1User2Id = versus.Team1User2Id,
                                Team1Score = versus.Team1Score,
                                Team2No = versus.Team2No,
                                Team2HeadUrl = team2.HeadUrl,
                                Team2User1Id = versus.Team2User1Id,
                                Team2User2Id = versus.Team2User2Id,
                                Team2Score = versus.Team2Score,
                                Team1ExtraScore = versus.Team1ExtraScore,
                                Team2ExtraScore = versus.Team2ExtraScore,
                                CreateTime = versus.CreateTime,
                            };
            var list = await queryable.OrderBy(m => m.IsExtra).ThenBy(m => m.LoopNo).ToListAsync();
            return list;
        }

        /// <summary>
        /// 淘汰赛对阵信息修改
        /// </summary>
        public async Task<UnaryResult> UpdateGameKnockoutVersusInfoAsync(List<GameKnockoutVersusUpdateDto> request)
        {
            if (request != null && request.Count > 0)
            {
                using (var uow = _unitOfWorkManager.Begin())
                {
                    foreach (var item in request)
                    {
                        var versus = await _gameKnockoutVersusRepository.FirstOrDefaultAsync(m => m.ID == item.ID);
                        if (versus == null)
                        {
                            return UnaryResult.Faild(10, "对阵信息不存在");
                        }

                        versus.Address = item.Address ?? versus.Address;
                        versus.StartTime = item.StartTime ?? versus.StartTime;
                        versus.EndTime = item.EndTime ?? versus.EndTime;
                        await _gameKnockoutVersusRepository.UpdateAsync(versus);
                    }

                    await uow.CompleteAsync();
                }
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 结束淘汰赛轮次比赛
        /// </summary>
        /// <param name="knockoutRoundsId">轮次ID</param>
        /// <returns></returns>
        public async Task<UnaryResult> FinishKnockoutRoundsAsync(Guid knockoutRoundsId)
        {
            var rounds = await _gameKnockoutRoundsRepository.FirstOrDefaultAsync(m => m.ID == knockoutRoundsId);
            if (rounds == null)
            {
                return UnaryResult.Faild(10, "淘汰赛轮次不存在");
            }

            if (await _gameKnockoutRoundsRepository.AnyAsync(m => m.GameId == rounds.GameId && m.VersusType == rounds.VersusType && m.KnockoutCount == rounds.KnockoutCount * 2 && !m.IsFinished))
            {
                return UnaryResult.Faild(10, "淘汰赛上个轮次未结束");
            }

            if (await _gameKnockoutVersusRepository.AnyAsync(m => m.KnockoutRoundsId == knockoutRoundsId && m.Team1Score == 0 && m.Team2Score == 0))
            {
                return UnaryResult.Faild(10, "本轮淘汰赛未全部完成");
            }

            rounds.IsFinished = true;
            var versusBuilder = await _gameKnockoutVersusRepository.UpdatePartialAsync();
            versusBuilder = versusBuilder.Set(m => m.IsFinished, true).Where(m => m.KnockoutRoundsId == knockoutRoundsId);
            using (var uow = _unitOfWorkManager.Begin())
            {
                await _gameKnockoutRoundsRepository.UpdateAsync(rounds);
                await versusBuilder.ExecuteAsync();
                await uow.CompleteAsync();
            }

            //结束比赛时，计算参赛队伍积分
            if (!await _gameKnockoutRoundsRepository.AnyAsync(m => m.GameId == rounds.GameId && !m.IsFinished))
            {
                var game = await _gameRepository.AsNoTracking().FirstOrDefaultAsync(m => m.ID == rounds.GameId);
                await FinishGameCalculatePointAsync(game);
            }

            return UnaryResult.Succeed();
        }

        /// <summary>
        /// 自动报名比赛
        /// </summary>
        public async Task<UnaryResult> AutoJoinAsync(Guid gameId, bool isDraw = false)
        {
            await AutoJoinGameAsync(gameId, isDraw);
            return UnaryResult.Succeed();
        }
    }
}